Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide better feedback to the user in case of invalid test classes #1286

Conversation

alb-i986
Copy link
Contributor

Only one exception per invalid test class is now fired, rather than one per validation error, with all of the validation errors as part of its message.
Example:

org.junit.runners.InvalidTestClassError: Invalid test class 'InvalidTest':
  1. Method staticAfterMethod() should not be static
  2. Method staticBeforeMethod() should not be static

Validation errors for the same test class now count only once in the failure count (Result#getFailureCount).

Implementation:

  • ParentRunner#validate throws InvalidTestClassError in case of validation errors
  • ErrorReportingRunner fires the InvalidTestClassError above without unpacking the causes

Follows how this change looks like in build tools.

Gradle 2.13

Before this change:

Invalid1Test > initializationError FAILED
    java.lang.Exception: Method staticAfterMethod() should not be static

Invalid1Test > initializationError FAILED
    java.lang.Exception: Method staticBeforeMethod() should not be static

Invalid2Test > initializationError FAILED
    java.lang.Exception: Method staticAfterMethod() should not be static

Invalid2Test > initializationError FAILED
    java.lang.Exception: Method staticBeforeMethod() should not be static

ValidTest > asd FAILED
    java.lang.AssertionError
        at ValidTest.asd(ValidTest.java:12)

5 tests completed, 5 failed
:test FAILED

After this change:

Invalid1Test > initializationError FAILED
    org.junit.runners.InvalidTestClassError: Invalid test class 'Invalid1Test':
      1. Method staticAfterMethod() should not be static
      2. Method staticBeforeMethod() should not be static

Invalid2Test > initializationError FAILED
    org.junit.runners.InvalidTestClassError: Invalid test class 'Invalid2Test':
      1. Method staticAfterMethod() should not be static
      2. Method staticBeforeMethod() should not be static

ValidTest > asd FAILED
    java.lang.AssertionError
        at ValidTest.asd(ValidTest.java:12)

3 tests completed, 3 failed
:test FAILED

maven-surefire-plugin 2.19.1 (on maven 3.3.9)

Before:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running Asd2Test
Tests run: 2, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 0.809 sec <<< FAILURE! - in Asd2Test
initializationError(Asd2Test)  Time elapsed: 0.098 sec  <<< ERROR!
java.lang.Exception: Method staticAfterMethod() should not be static

initializationError(Asd2Test)  Time elapsed: 0.01 sec  <<< ERROR!
java.lang.Exception: Method staticBeforeMethod() should not be static

Running AsdTest
Tests run: 2, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 0.001 sec <<< FAILURE! - in AsdTest
initializationError(AsdTest)  Time elapsed: 0 sec  <<< ERROR!
java.lang.Exception: Method staticAfterMethod() should not be static

initializationError(AsdTest)  Time elapsed: 0 sec  <<< ERROR!
java.lang.Exception: Method staticBeforeMethod() should not be static

Running WorkingTest
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec <<< FAILURE! - in WorkingTest
asd(WorkingTest)  Time elapsed: 0.001 sec  <<< FAILURE!
java.lang.AssertionError: asd
    at WorkingTest.asd(WorkingTest.java:12)


Results :

Failed tests: 
  WorkingTest.asd:12 asd
Tests in error: 
Asd2Test.initializationError(Asd2Test)
  Run 1: Asd2Test.initializationError »  Method staticAfterMethod() should not be stati...
  Run 2: Asd2Test.initializationError »  Method staticBeforeMethod() should not be stat...

AsdTest.initializationError(AsdTest)
  Run 1: AsdTest.initializationError »  Method staticAfterMethod() should not be static
  Run 2: AsdTest.initializationError »  Method staticBeforeMethod() should not be stati...


Tests run: 3, Failures: 1, Errors: 2, Skipped: 0

After:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running Asd2Test
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 1.29 sec <<< FAILURE! - in Asd2Test
initializationError(Asd2Test)  Time elapsed: 0.095 sec  <<< ERROR!
org.junit.runners.InvalidTestClassError: 
Invalid test class 'Asd2Test':
  1. Method staticAfterMethod() should not be static
  2. Method staticBeforeMethod() should not be static

Running AsdTest
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.001 sec <<< FAILURE! - in AsdTest
initializationError(AsdTest)  Time elapsed: 0.001 sec  <<< ERROR!
org.junit.runners.InvalidTestClassError: 
Invalid test class 'AsdTest':
  1. Method staticAfterMethod() should not be static
  2. Method staticBeforeMethod() should not be static

Running WorkingTest
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0 sec <<< FAILURE! - in WorkingTest
asd(WorkingTest)  Time elapsed: 0 sec  <<< FAILURE!
java.lang.AssertionError: asd
    at WorkingTest.asd(WorkingTest.java:12)


Results :

Failed tests: 
  WorkingTest.asd:12 asd
Tests in error: 
  Asd2Test.initializationError » InvalidTestClass Invalid test class 'Asd2Test':...
  AsdTest.initializationError » InvalidTestClass Invalid test class 'AsdTest':
 ...

Tests run: 3, Failures: 1, Errors: 2, Skipped: 0

Please note that maven-surefire-plugin 2.19.1 is already smart enough to compact the different validation errors for the same test class together, in the Results section. With the change I'm proposing here, build tools won't need this extra logic.

Only one exception per invalid test class is now fired, rather than one per validation error,
with all of the validation errors as part of its message.
Example:

    org.junit.runners.InvalidTestClassError: Invalid test class 'InvalidTest':
      1. Method staticAfterMethod() should not be static
      2. Method staticBeforeMethod() should not be static

Validation errors for the same test class now count only once in the failure count (Result#getFailureCount).

Implementation:
 - ParentRunner#validate throws InvalidTestClassError in case of validation errors
 - ErrorReportingRunner fires the InvalidTestClassError above without unpacking the causes
}

@Test
public void givenInvalidTestClass_integrationTest() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note the integration test here. I'm not sure if this is a good place for it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine. Thanks!

@kcooney
Copy link
Member

kcooney commented Apr 29, 2016

I really like this. @junit-team/junit-committers any thoughts?

@marcphilipp
Copy link
Member

👍

@@ -121,7 +121,7 @@ public void numbers(int x) {
public void dataPointFieldsMustBeStatic() {
assertThat(
testResult(DataPointFieldsMustBeStatic.class),
CoreMatchers.<PrintableResult>both(failureCountIs(2))
CoreMatchers.<PrintableResult>both(failureCountIs(1))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verifying the failure count does not make sense anymore. I think it should be removed. @junit-team/junit-committers What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stefanbirkner only at line 123 or do you mean all of the tests asserting on result.failureCount?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've applied this to some other tests where it made sense. See d5fc61c.
Please take a look @stefanbirkner
Thanks

@stefanbirkner
Copy link
Contributor

+1

@alb-i986
Copy link
Contributor Author

Should be ready to be squashed and then merged.

sb.append(String.format("Invalid test class '%s':", testClass.getName()));
int i = 1;
for (Throwable error : validationErrors) {
sb.append("\n " + i++ + ". " + error.getMessage());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "\n " + (i++) + ". " would be more readable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, thanks

@alb-i986
Copy link
Contributor Author

Fixed conflicts with master

@@ -0,0 +1,43 @@
package org.junit.runners;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this class should be in the org.junit.runners.model package (with InitializationError etc.).

@marcphilipp
Copy link
Member

@alb-i986 I found another minor thing. Sorry!

@alb-i986
Copy link
Contributor Author

@marcphilipp done

@marcphilipp
Copy link
Member

Thanks, looks good to me!

@junit-team/junit-committers Please take a look. :-)

@kcooney
Copy link
Member

kcooney commented May 20, 2016

LGTM

package org.junit.runners.model;

import org.junit.Test;
import org.junit.runners.model.InvalidTestClassError;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This import is unused now, isn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, thanks! Fixed now

public class InvalidTestClassError extends InitializationError {
private static final long serialVersionUID = 1L;

private final Class<?> testClass;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we have to store testClass since it's only used in the constructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhm ya right.

@marcphilipp marcphilipp merged commit 0e4cb7e into junit-team:master Jun 23, 2016
@marcphilipp
Copy link
Member

@alb-i986 Thanks for your hard work! Please add a description of this improvement to the draft of the release notes.

@alb-i986 alb-i986 deleted the ErrorReportingRunner-provide-better-feedback branch June 23, 2016 20:01
@marcphilipp
Copy link
Member

@alb-i986 Merging this broke the build on JDK 5. Can you please take a look? https://junit.ci.cloudbees.com/job/JUnit/78/console

@alb-i986
Copy link
Contributor Author

alb-i986 commented Jun 25, 2016

Sorry about that, should be fixed by #1333 . I'm on a mobile phone now so i can't do any m
ore than that.

How come Travis didn't catch that anyways?

@alb-i986
Copy link
Contributor Author

@marcphilipp

@alb-i986 Thanks for your hard work! Please add a description of this improvement to the draft of the release notes.

Done:

https://github.com/junit-team/junit4/wiki/4.13-Release-Notes#pull-request-1286-provide-better-feedback-to-the-user-in-case-of-invalid-test-classes

Please let me know if you're happy enough.
Thanks.

@marcphilipp
Copy link
Member

Great, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants